﻿namespace WebPacker.Packs.Resources
{
	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Text;
	using WebPacker.Helpers;

	public sealed class WildcardFileResource : IResource, ICompositeResource
	{
		private readonly string path;
		private readonly string searchPattern;

		public WildcardFileResource(string fileName)
			: this(fileName, Encoding.UTF8)
		{
		}

		public WildcardFileResource(string fileName, Encoding encoding)
		{
			if (fileName == null)
			{
				throw new ArgumentNullException("fileName");
			}

			if (encoding == null)
			{
				throw new ArgumentNullException("encoding");
			}

			CheckPath(fileName);

			Name = VirtualPathHelper.NormalizePath(fileName);
			Encoding = encoding;

			var index = Name.LastIndexOf(Path.DirectorySeparatorChar);

			if (index > 0)
			{
				if (index == Name.Length - 1)
				{
					throw new ArgumentException("File name \"{0}\" is invalid.", Name);
				}

				path = Name.Substring(0, index);
				searchPattern = Name.Substring(index + 1);
			}
			else
			{
				path = string.Empty;
				searchPattern = Name;
			}
		}

		public string Name
		{
			get;
			private set;
		}

		public string SearchPath
		{
			get { return path; }
		}

		public string SearchPattern
		{
			get { return searchPattern; }
		}

		public Encoding Encoding { get; set; }

		public string GetContent()
		{
			var contents = new List<string>();

			foreach (var resource in GetResources())
			{
				contents.Add(resource.GetContent());
			}

			return String.Concat(contents.ToArray());
		}

		public DateTime GetLastModifiedTime()
		{
			var maxLastModified = DateTime.MinValue;

			foreach (var name in GetFileNames())
			{
				var lastModified = File.GetLastWriteTime(name);

				if (lastModified > maxLastModified)
				{
					maxLastModified = lastModified;
				}
			}

			return maxLastModified;
		}

		public IEnumerable<IResource> GetResources()
		{
			var names = GetFileNames();
			var resources = new IResource[names.Length];

			for (var i = 0; i < names.Length; i++)
			{
				resources[i] = new FileResource(names[i], Encoding);
			}

			return resources;
		}

		internal string[] GetFileNames()
		{
			var names = Directory.GetFiles(path, searchPattern);
			Array.Sort(names);
			return names;
		}

		private static void CheckPath(string path)
		{
			for (int i = 0; i < path.Length; i++)
			{
				int symbol = path[i];

				// < > | system
				if (symbol == 0x22 || symbol == 0x3c || symbol == 0x3e || symbol == 0x7c || symbol < 0x20)
				{
					throw new ArgumentException(string.Format("File name \"{0}\" is invalid.", path));
				}
			}
		}
	}
}
